/*
* Copyright (c) 2016 ShopJsp. All Rights Reserved.
 * ============================================================================
 * 版权所有 2011 - 今 北京华宇盈通科技有限公司，并保留所有权利。
 * ----------------------------------------------------------------------------
 * 提示：在未取得SHOPJSP商业授权之前，您不能将本软件应用于商业用途，否则SHOPJSP将保留追究的权力。
 * ----------------------------------------------------------------------------
 * 官方网站：http://www.shopjsp.com
 * ============================================================================
*/
package com.hyyt.shopjsp.util.interceptor;


import com.hyyt.shopjsp.util.common.StringStaticKey;
import com.hyyt.shopjsp.util.exception.TokenException;
import com.hyyt.shopjsp.util.redis.util.RedisDataReadUtil;
import org.apache.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.UUID;

/**
 * 定义token 滥交拦截器,处理表重复提交
 * 原理：先生成token放入session然后提交表单与服务器获得的数据对比，之后删除token.当第二次提交时，session已不存在，至此可防止表单重复提交。
 * 用法：1、生成表单的方法前加入@Token(save=true)
 * ------2、发保存表单的方法前加入@Token(remove=true)
 * ------3、表单内加入：<input type="hidden" name="token" value="${token}"/>
 *
 * @data ankang on 2016/8/16 0016.
 */
public class TokenInterceptor extends HandlerInterceptorAdapter {

    private static Logger logger = Logger.getLogger(TokenInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            String basePath = RedisDataReadUtil.getSysConfig(StringStaticKey.BASE_PATH);            //读取项目根路径
            Token annotation = method.getAnnotation(Token.class);                                   //读取注解token
            if (annotation != null) {                                                               //判断是否有token
                boolean needSaveSession = annotation.save();                                        //获取初次进入表单标识
                if (needSaveSession) {                                                              //判断是否初次进入表单
                    request.getSession(false).setAttribute("token", UUID.randomUUID().toString());//生成token
                }
                boolean needRemoveSession = annotation.remove();                                   //获取表单已提交标识
                if (needRemoveSession) {                                                            //判断表单是否已提交
                    if (isRepeatSubmit(request)) {                                                  //如果是重复提交操作则进入提示页面
                        throw new TokenException("表单重复提交");
                        /*RequestDispatcher dispatcher = request.getRequestDispatcher(basePath + "/WEB-INF/error/no_repeat.jsp");
                        dispatcher.forward(request, response);
                        return false;*/
                    }
                    request.getSession(false).removeAttribute("token");                            //token验证完进行删除
                }
            }
            return true;
        } else {
            return super.preHandle(request, response, handler);
        }
    }

    /**
     * 是否重叠提交判断
     *
     * @param request
     * @return
     */
    private boolean isRepeatSubmit(HttpServletRequest request) {
        String serverToken = (String) request.getSession(false).getAttribute("token");
        if (serverToken == null) {
            return true;
        }
        String clinetToken = request.getParameter("token");
        if (clinetToken == null) {
            return true;
        }
        if (!serverToken.equals(clinetToken)) {
            return true;
        }
        return false;
    }
}
